`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2020/10/29 16:56:31
// Design Name: 
// Module Name: hazard_unit
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module hazard_unit(
    input logic             memwrite_d,
    input logic             branch_d,
    input logic [ 4: 0]     rs_d,rt_d,rd_d,    
    input logic [ 4: 0]     alucontrol_d,
    input logic [ 4: 0]     rs_e,rt_e,rd_e,
    input logic [ 4: 0]     write_reg_e,
    input logic             memtoreg_e,
    input logic             regwrite2_e,
    input logic             memtoreg_m,
    input logic             regwrite_m,
    input logic [ 4: 0]     write_reg_m,
    input logic [ 4: 0]     write_reg_w,
    input logic             regwrite_w,
    input logic [ 4: 0]     alucontrol_e,
    input logic [ 1: 0]     hilowrite_m,
    input logic [ 1: 0]     hilowrite_w,
    input logic             stallreq_alu_e,
    input logic             pcsrc2_d,
    input logic             cp0_we_m,
    input logic             exc_flag_i,
    input logic  [ 7: 0]    cp0_radr_e,
    input logic  [ 7: 0]    cp0_wadr_m,

    output logic            cp0_reg_data_src_e,
    output logic [ 1: 0]    hi_src_e,
    output logic [ 1: 0]    lo_src_e,
    output logic [ 1: 0]    forward_a_e,forward_b_e,//forward_c_e,
    output logic            forward_a_d,forward_b_d,
    output logic            stall_f,stall_d,stall_e,
    output logic            flush_f,flush_d,flush_e,flush_m,flush_w
    );

    logic lwstall;
    logic branchstall;
    logic swstall;
    logic j_rs_stall;
    
    //solving data hazard with forwarding
    always_comb begin
        if ((rs_e != 0)&&(rs_e == write_reg_m)&&regwrite_m) begin
            forward_a_e = 2'b10;
        end else if ((rs_e != 0)&&(rs_e == write_reg_w)&&regwrite_w) begin
            forward_a_e = 2'b01;
        end else begin
            forward_a_e = 2'b00;
        end
    
        if ((rt_e != 0)&&(rt_e == write_reg_m)&&regwrite_m) begin
            forward_b_e = 2'b10;
        end else if ((rt_e != 0)&&(rt_e == write_reg_w)&&regwrite_w) begin
            forward_b_e = 2'b01;
        end else begin
            forward_b_e = 2'b00;
        end

        // if ((rd_e != 0)&&(rd_e == write_reg_m)&&regwrite_m) begin
        //     forward_c_e = 2'b10;
        // end else if ((rd_e != 0)&&(rd_e == write_reg_w)&&regwrite_w) begin
        //     forward_c_e = 2'b01;
        // end else begin
        //     forward_c_e = 2'b00;
        // end

        forward_a_d = (rs_d != 0)&&(rs_d == write_reg_m)&&regwrite_m;
        forward_b_d = (rt_d != 0)&&(rt_d == write_reg_m)&&regwrite_m;

    end

    //solving data hazard with stalls
    always_comb begin
        lwstall = ((rs_d == rt_e)|(rt_d == rt_e))&&memtoreg_e;
        branchstall = (branch_d&&regwrite2_e&&(write_reg_e == rs_d|write_reg_e == rt_d))
                            |(branch_d&&memtoreg_m&&(write_reg_m == rs_d|write_reg_m == rt_d));
        j_rs_stall = (pcsrc2_d&&regwrite2_e&&(write_reg_e == rs_d));
        swstall = (memwrite_d&&regwrite2_e&&(write_reg_e == rt_d))|(memwrite_d&&memtoreg_m&&(write_reg_m == rt_d)); 
        if(exc_flag_i) begin
            flush_f = 1'b1;
            flush_d = 1'b1;
            flush_e = 1'b1;
            flush_m = 1'b1;
            flush_w = 1'b1;
        end
        else if (stallreq_alu_e) begin
            stall_f = 1'b1;
            stall_d = 1'b1;
            stall_e = 1'b1;
            flush_e = 1'b0;
            flush_m = 1'b1;    
        end
        else if (lwstall|(branchstall|swstall|j_rs_stall)) begin
            stall_f = 1'b1;
            stall_d = 1'b1;
            stall_e = 1'b0;
            flush_e = 1'b1;
            flush_m = 1'b0;
        end 
        else begin
            stall_f = 1'b0;
            stall_d = 1'b0;
            stall_e = 1'b0;
            flush_f = 1'b0;
            flush_d = 1'b0;
            flush_e = 1'b0;
            flush_m = 1'b0;
            flush_w = 1'b0;
        end
    end

    //solving data hazard(mfc0,mtc0) with forwarding
    assign cp0_reg_data_src_e = ( (cp0_we_m && alucontrol_e == 5'b11001) &&
                                  (cp0_radr_e == cp0_wadr_m))? 1'b1: 1'b0; 
    
    //solving data hazard(mthi,mtlo,mfhi,mflo) with forwarding
    always_comb begin
       if((hilowrite_m == 2'b01 || hilowrite_m == 2'b11)
          &&alucontrol_e == 5'b10000) begin
           hi_src_e = 2'b01;
       end else if(hilowrite_w == 2'b01 || hilowrite_w == 2'b11
          &&alucontrol_e == 5'b10000) begin
           hi_src_e = 2'b10;
       end else begin
           hi_src_e = 2'b00;
       end

       if((hilowrite_m == 2'b10 || hilowrite_m == 2'b11)
          &&alucontrol_e == 5'b10001) begin
           lo_src_e = 2'b01;
       end else if(hilowrite_w == 2'b10 || hilowrite_w == 2'b11
          &&alucontrol_e == 5'b10001) begin
           lo_src_e = 2'b10;
       end else begin
           lo_src_e = 2'b00;
       end
    end


endmodule
